home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / hack / 3_1_3 / win / x11 / wintext.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-24  |  10.1 KB  |  388 lines

  1. /*    SCCS Id: @(#)wintext.c    3.1    92/3/7
  2. /* Copyright (c) Dean Luick, 1992                  */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /*
  6.  * File for dealing with text windows.
  7.  * 
  8.  *     + No global functions.
  9.  */
  10.  
  11. #ifndef SYSV
  12. #define PRESERVE_NO_SYSV    /* X11 include files may define SYSV */
  13. #endif
  14.  
  15. #include <X11/Intrinsic.h>
  16. #include <X11/StringDefs.h>
  17. #include <X11/Shell.h>
  18. #include <X11/Xos.h>
  19. #include <X11/Xaw/AsciiText.h>
  20. #include <X11/Xaw/Cardinals.h>
  21. #include <X11/Xatom.h>
  22.  
  23. #ifdef PRESERVE_NO_SYSV
  24. # ifdef SYSV
  25. #  undef SYSV
  26. # endif
  27. # undef PRESERVE_NO_SYSV
  28. #endif
  29.  
  30. #include "hack.h"
  31. #include "winX.h"
  32.  
  33.  
  34. #define TRANSIENT_TEXT    /* text window is a transient window (no positioning) */
  35.  
  36. static const char text_translations[] =
  37.     "#override\n\
  38.      <BtnDown>: dismiss_text()\n\
  39.      <Key>: key_dismiss_text()";
  40.  
  41.  
  42. /*ARGSUSED*/
  43. void
  44. delete_text(w, event, params, num_params)
  45.     Widget w;
  46.     XEvent *event;
  47.     String *params;
  48.     Cardinal *num_params;
  49. {
  50.     struct xwindow *wp;
  51.     struct text_info_t *text_info;
  52.  
  53.     wp = find_widget(w);
  54.     text_info = wp->text_information;
  55.  
  56.     nh_XtPopdown(w);
  57.  
  58.     if (text_info->blocked) {
  59.     exit_x_event = TRUE;
  60.     } else if (text_info->destroy_on_ack) {
  61.     destroy_text_window(wp);
  62.     }
  63. }
  64.  
  65. /*
  66.  * Callback used for all text windows.  The window is poped down on any key
  67.  * or button down event.  It is destroyed if the main nethack code is done
  68.  * with it.
  69.  */
  70. /*ARGSUSED*/
  71. void
  72. dismiss_text(w, event, params, num_params)
  73.     Widget w;
  74.     XEvent *event;
  75.     String *params;
  76.     Cardinal *num_params;
  77. {
  78.     struct xwindow *wp;
  79.     struct text_info_t *text_info;
  80.     Widget popup = XtParent(w);
  81.  
  82.     wp = find_widget(w);
  83.     text_info = wp->text_information;
  84.  
  85.     nh_XtPopdown(popup);
  86.  
  87.     if (text_info->blocked) {
  88.     exit_x_event = TRUE;
  89.     } else if (text_info->destroy_on_ack) {
  90.     destroy_text_window(wp);
  91.     }
  92. }
  93.  
  94. /* Dismiss when a non-modifier key pressed. */
  95. void
  96. key_dismiss_text(w, event, params, num_params)
  97.     Widget w;
  98.     XEvent *event;
  99.     String *params;
  100.     Cardinal *num_params;
  101. {
  102.     char ch = key_event_to_char((XKeyEvent *) event);
  103.     if (ch) dismiss_text(w, event, params, num_params);
  104. }
  105.  
  106. /* ARGSUSED */
  107. void
  108. add_to_text_window(wp, attr, str)
  109.     struct xwindow *wp;
  110.     int attr;    /* currently unused */
  111.     const char *str;
  112. {
  113.     struct text_info_t *text_info = wp->text_information;
  114.     int width;
  115.  
  116.     append_text_buffer(&text_info->text, str, FALSE);
  117.  
  118.     /* Calculate text width and save longest line */
  119.     width = XTextWidth(text_info->fs, str, (int) strlen(str));
  120.     if (width > text_info->max_width)
  121.     text_info->max_width = width;
  122. }
  123.  
  124. void
  125. display_text_window(wp, blocking)
  126.     struct xwindow *wp;
  127.     boolean blocking;
  128. {
  129.     struct text_info_t *text_info;
  130.     Arg args[8];
  131.     Cardinal num_args;
  132.     Dimension width, height;
  133.     int nlines;
  134.  
  135.     text_info = wp->text_information;
  136.     width  = text_info->max_width + text_info->extra_width;
  137.     text_info->blocked = blocking;
  138.     text_info->destroy_on_ack = FALSE;
  139.  
  140.     /*
  141.      * Calculate the number of lines to use.  First, find the number of
  142.      * lines that would fit on the screen.  Next, remove four of these
  143.      * lines to give room for a possible window manager titlebar (some
  144.      * wm's put a titlebar on transient windows).  Make sure we have
  145.      * _some_ lines.  Finally, use the number of lines in the text if
  146.      * there are fewer than the max.
  147.      */
  148.     nlines = (XtScreen(wp->w)->height - text_info->extra_height) /
  149.             (text_info->fs->ascent + text_info->fs->descent);
  150.     nlines -= 4;
  151.     if (nlines <= 0) nlines = 1;
  152.  
  153.     if (nlines > text_info->text.num_lines)
  154.     nlines = text_info->text.num_lines;
  155.  
  156.     /* Font height is ascent + descent. */
  157.     height = (nlines * (text_info->fs->ascent + text_info->fs->descent))
  158.                             + text_info->extra_height;
  159.  
  160.     num_args = 0;
  161.  
  162.     if (nlines < text_info->text.num_lines) {
  163.     /* add on width of scrollbar.  Really should look this up,
  164.      * but can't until the window is realized.  Chicken-and-egg problem.
  165.      */
  166.     width += 20;
  167.     }
  168.  
  169.     if (width > (Dimension) XtScreen(wp->w)->width) { /* too wide for screen */
  170.     /* Back off some amount - we really need to back off the scrollbar */
  171.     /* width plus some extra.                       */
  172.     width = XtScreen(wp->w)->width - 20;
  173.     }
  174.     XtSetArg(args[num_args], XtNstring, text_info->text.text);    num_args++;
  175.     XtSetArg(args[num_args], XtNwidth,  width);            num_args++;
  176.     XtSetArg(args[num_args], XtNheight, height);        num_args++;
  177.     XtSetValues(wp->w, args, num_args);
  178.  
  179. #ifdef TRANSIENT_TEXT
  180.     XtRealizeWidget(wp->popup);
  181.     XSetWMProtocols(XtDisplay(wp->popup), XtWindow(wp->popup), 
  182.             &wm_delete_window, 1);
  183.     positionpopup(wp->popup, FALSE);
  184. #endif
  185.  
  186.     nh_XtPopup(wp->popup, (int)XtGrabNone, wp->w);
  187.  
  188.     /* Kludge alert.  Scrollbars are not sized correctly by the Text widget */
  189.     /* if added before the window is displayed, so do it afterward. */
  190.     num_args = 0;
  191.     if (nlines < text_info->text.num_lines) {    /* add vert scrollbar */
  192.     XtSetArg(args[num_args], XtNscrollVertical, XawtextScrollAlways);
  193.                                 num_args++;
  194.     }
  195.     if (width >= (Dimension) (XtScreen(wp->w)->width-20)) {    /* too wide */
  196.     XtSetArg(args[num_args], XtNscrollHorizontal, XawtextScrollAlways);
  197.                                 num_args++;
  198.     }
  199.     if (num_args) XtSetValues(wp->w, args, num_args);
  200.  
  201.     /* We want the user to acknowlege. */
  202.     if (blocking) {
  203.     (void) x_event(EXIT_ON_EXIT);
  204.     nh_XtPopdown(wp->popup);
  205.     }
  206. }
  207.  
  208.  
  209. void
  210. create_text_window(wp)
  211.     struct xwindow *wp;
  212. {
  213.     struct text_info_t *text_info;
  214.     Arg args[8];
  215.     Cardinal num_args;
  216.     Position top_margin, bottom_margin, left_margin, right_margin;
  217.  
  218.     wp->type = NHW_TEXT;
  219.  
  220.     wp->text_information = text_info = 
  221.             (struct text_info_t *) alloc(sizeof(struct text_info_t));
  222.  
  223.     init_text_buffer(&text_info->text);
  224.     text_info->max_width      = 0;
  225.     text_info->extra_width    = 0;
  226.     text_info->extra_height   = 0;
  227.     text_info->blocked          = FALSE;
  228.     text_info->destroy_on_ack = TRUE;    /* Ok to destroy before display */
  229.  
  230.     num_args = 0;
  231.     XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
  232.  
  233. #ifdef TRANSIENT_TEXT
  234.     wp->popup = XtCreatePopupShell("text", transientShellWidgetClass,
  235.                    toplevel, args, num_args);
  236. #else
  237.     wp->popup = XtCreatePopupShell("text", topLevelShellWidgetClass,
  238.                    toplevel, args, num_args);
  239. #endif
  240.     XtOverrideTranslations(wp->popup,
  241.     XtParseTranslationTable("<Message>WM_PROTOCOLS: delete_text()"));
  242.  
  243.     num_args = 0;
  244.     XtSetArg(args[num_args], XtNdisplayCaret, False);        num_args++;
  245.     XtSetArg(args[num_args], XtNresize, XawtextResizeBoth);    num_args++;
  246.     XtSetArg(args[num_args], XtNtranslations,
  247.         XtParseTranslationTable(text_translations));    num_args++;
  248.  
  249.     wp->w = XtCreateManagedWidget(
  250.         killer && WIN_MAP == WIN_ERR ?
  251.                   "tombstone" : "text_text", /* name */
  252.         asciiTextWidgetClass,
  253.         wp->popup,        /* parent widget */
  254.         args,            /* set some values */
  255.         num_args);        /* number of values to set */
  256.  
  257.     /* Get the font and margin information. */
  258.     num_args = 0;
  259.     XtSetArg(args[num_args], XtNfont,          &text_info->fs); num_args++;
  260.     XtSetArg(args[num_args], XtNtopMargin,    &top_margin);    num_args++;
  261.     XtSetArg(args[num_args], XtNbottomMargin, &bottom_margin); num_args++;
  262.     XtSetArg(args[num_args], XtNleftMargin,   &left_margin);   num_args++;
  263.     XtSetArg(args[num_args], XtNrightMargin,  &right_margin);  num_args++;
  264.     XtGetValues(wp->w, args, num_args);
  265.  
  266.     text_info->extra_width  = left_margin + right_margin;
  267.     text_info->extra_height = top_margin + bottom_margin;
  268. }
  269.  
  270. void
  271. destroy_text_window(wp)
  272.     struct xwindow *wp;
  273. {
  274.     /* Don't need to pop down, this only called from dismiss_text(). */
  275.  
  276.     struct text_info_t *text_info = wp->text_information;
  277.  
  278.     /*
  279.      * If the text window was blocked, then the user has already ACK'ed
  280.      * it and we are free to really destroy the window.  Otherwise, don't
  281.      * destroy until the user dismisses the window via a key or button
  282.      * press.
  283.      */
  284.     if (text_info->blocked || text_info->destroy_on_ack) {
  285.     XtDestroyWidget(wp->popup);
  286.     free_text_buffer(&text_info->text);
  287.     free((char *) text_info);
  288.     wp->type = NHW_NONE;    /* allow reuse */
  289.     } else {
  290.     text_info->destroy_on_ack = TRUE;    /* destroy on next ACK */
  291.     }
  292. }
  293.  
  294.  
  295. /* text buffer routines ---------------------------------------------------- */
  296.  
  297. /* Append a line to the text buffer. */
  298. void
  299. append_text_buffer(tb, str, concat)
  300.     struct text_buffer *tb;
  301.     const char *str;
  302.     boolean concat;
  303. {
  304.     char *copy;
  305.     int length;
  306.  
  307.     if (!tb->text) panic("append_text_buffer:  null text buffer");
  308.  
  309.     if (str) {
  310.     length = strlen(str);
  311.     } else {
  312.     length = 0;
  313.     }
  314.  
  315.     if (length + tb->text_last + 1 >= tb->text_size) {
  316.     /* we need to go to a bigger buffer! */
  317. #ifdef VERBOSE
  318.     printf("append_text_buffer: text buffer growing from %d to %d bytes\n",
  319.                 tb->text_size, 2*tb->text_size);
  320. #endif
  321.     copy = (char *) alloc(tb->text_size*2);
  322.     (void) memcpy(copy, tb->text, tb->text_last);
  323.     free(tb->text);
  324.     tb->text = copy;
  325.     tb->text_size *= 2;
  326.     }
  327.  
  328.     if (tb->num_lines) {    /* not first --- append a newline */
  329.     char appchar = '\n';
  330.  
  331.     if(concat && !index("!.?'\")", tb->text[tb->text_last-1])) {
  332.         appchar = ' ';
  333.         tb->num_lines--; /* offset increment at end of function */
  334.     }
  335.  
  336.     *(tb->text + tb->text_last) = appchar;
  337.     tb->text_last++;
  338.     }
  339.  
  340.     if (str) {
  341.     (void) memcpy((tb->text+tb->text_last), str, length+1);
  342.     if(length) {
  343.         /* Remove all newlines. Otherwise we have a confused line count. */
  344.         copy = (tb->text+tb->text_last);
  345.         while (copy = index(copy, '\n'))
  346.         *copy = ' ';
  347.     }
  348.  
  349.     tb->text_last += length;
  350.     }
  351.     tb->text[tb->text_last] = '\0';
  352.     tb->num_lines++;
  353. }
  354.  
  355. /* Initialize text buffer. */
  356. void
  357. init_text_buffer(tb)
  358.     struct text_buffer *tb;
  359. {
  360.     tb->text      = (char *) alloc(START_SIZE);
  361.     tb->text[0]   = '\0';
  362.     tb->text_size = START_SIZE;
  363.     tb->text_last = 0;
  364.     tb->num_lines = 0;
  365. }
  366.  
  367. /* Empty the text buffer */
  368. void
  369. clear_text_buffer(tb)
  370.     struct text_buffer *tb;
  371. {
  372.     tb->text_last = 0;
  373.     tb->text[0]   = '\0';
  374.     tb->num_lines = 0;
  375. }
  376.  
  377. /* Free up allocated memory. */
  378. void
  379. free_text_buffer(tb)
  380.     struct text_buffer *tb;
  381. {
  382.     free(tb->text);
  383.     tb->text = (char *) 0;
  384.     tb->text_size = 0;
  385.     tb->text_last = 0;
  386.     tb->num_lines = 0;
  387. }
  388.